package com.tea.aop;

import com.tea.utils.Result;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * 写接口统一请求日志切面：POST / PUT / DELETE
 */
@Aspect
@Component
@Slf4j
public class WriteApiLoggingAspect {

    @Pointcut("execution(* com.tea.controller..*(..))")
    public void controllerMethods() {}

    @Around("controllerMethods()")
    public Object aroundController(ProceedingJoinPoint pjp) throws Throwable {
        ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attrs != null ? attrs.getRequest() : null;

        // 仅记录写操作
        String httpMethod = request != null ? request.getMethod() : "";
        boolean isWrite = "POST".equalsIgnoreCase(httpMethod)
                || "PUT".equalsIgnoreCase(httpMethod)
                || "DELETE".equalsIgnoreCase(httpMethod);

        if (!isWrite) {
            return pjp.proceed();
        }

        String uri = request != null ? request.getRequestURI() : "";
        String clientIp = request != null ? getClientIp(request) : "";
        String traceId = MDC.get("traceId");

        String classMethod = pjp.getSignature().toShortString();
        Object[] args = pjp.getArgs();

        long start = System.currentTimeMillis();
        try {
            log.info("[WRITE-REQ] method={}, uri={}, ip={}, traceId={}, target={}, argsCount={}",
                    httpMethod, uri, clientIp, traceId, classMethod, args != null ? args.length : 0);

            Object result = pjp.proceed();

            long cost = System.currentTimeMillis() - start;
            if (result instanceof Result) {
                Result<?> r = (Result<?>) result;
                log.info("[WRITE-RESP] uri={}, traceId={}, status={}, msg={}, cost={}ms",
                        uri, traceId, r.isSuccess(), r.getMessage(), cost);
            } else {
                log.info("[WRITE-RESP] uri={}, traceId={}, respType={}, cost={}ms",
                        uri, traceId, result != null ? result.getClass().getSimpleName() : "null", cost);
            }
            return result;
        } catch (Throwable ex) {
            long cost = System.currentTimeMillis() - start;
            log.error("[WRITE-ERROR] method={}, uri={}, ip={}, traceId={}, target={}, cost={}ms, ex={}",
                    httpMethod, uri, clientIp, traceId, classMethod, cost, ex.getMessage(), ex);
            throw ex;
        }
    }

    private String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        // 可能存在多级代理，取第一个
        if (ip != null && ip.contains(",")) {
            ip = ip.split(",")[0].trim();
        }
        return ip;
    }
}